
package galaxy.app.route;

import galaxy.app.Galaxy;
import galaxy.app.event.EventSystem;
import galaxy.app.log.LogHelper;
import galaxy.kernel.Constants;
import galaxy.kernel.Constants.Component;
import galaxy.kernel.annotation.Route;
import galaxy.kernel.exception.CoreException;
import galaxy.kernel.system.AbstractECSSystem;

import java.lang.reflect.Method;
import java.util.Collection;

/**
 * route component
 *
 */
public class RouteSystem extends AbstractECSSystem {

    RouteComponent c;

    EventSystem event;

    public RouteSystem() {
        c = Galaxy.components().getSingle(RouteComponent.class);
        event = Galaxy.systems().get(EventSystem.class);
    }
    
    public String name() {
        return Constants.Component.ROUTE;
    }

    @Override
    public void start() {
    }

    // @Override
    // public void afterStart() {
    // }

    // @Override
    // public void stop() {
    // }

    // @Override
    // public void beforeStop() {

    // }

    public RouteInfo getRouteInfo(String route) {
        return c.routeMaps.get(route);
    }

    public int getThreadId(String route) {
        RouteInfo routeInfo = getRouteInfo(route);
        return routeInfo.threadId;
    }

    private void addRouteInfo(RouteInfo routeInfo) {
        if (c.routeMaps.containsKey(routeInfo.routeName)) {
            LogHelper.warn("----------------> route= {} contains in route maps", routeInfo.routeName);
            throw new CoreException("routeName duplicate");
        }
        c.routeMaps.put(routeInfo.routeName, routeInfo);
        LogHelper.debug("add routename : {}",routeInfo.routeName);
    }

    public void putAll(Collection<BaseRoute> baseRoutes) {
        for (BaseRoute route : baseRoutes) {
            put(route);
        }
    }

    public void putAll(BaseRoute... baseRoutes) {
        for (BaseRoute route : baseRoutes) {
            put(route);
        }
    }

    public void put(BaseRoute instance) {
        if (instance == null) {
            return;
        }

        Class<?> clazz = getAnnotationClazz(instance);
        if (clazz == null) {
            LogHelper.warn("BaseRoute not use @Route annotation. class = {}", instance.getClass().getName());
            return;
        }

        Route routeAnnotation = clazz.getAnnotation(Route.class);
        Method[] methodArray = clazz.getMethods();
        for (Method method : methodArray) {
            method.setAccessible(true);

            RouteInfo routeInfo = RouteInfo.valueOf(instance, clazz, routeAnnotation, method);
            if(routeInfo != null) {
                this.addRouteInfo(routeInfo);
            }
        }

        event.register(instance);
    }

    private Class<?> getAnnotationClazz(BaseRoute instance) {
        Class<?> annotationClazz = null;
        Route annotationRoute = instance.getClass().getAnnotation(Route.class);
        if (annotationRoute != null) {
            annotationClazz = instance.getClass();
        } else {
            Class<?>[] interfacesClazz = instance.getClass().getInterfaces();
            for (Class<?> clazz : interfacesClazz) {
                annotationRoute = clazz.getAnnotation(Route.class);
                if (annotationRoute != null) {
                    annotationClazz = clazz;
                    break;
                }
            }
        }
        return annotationClazz;
    }
}
